home *** CD-ROM | disk | FTP | other *** search
/ Greenhouse Effect Detection Expriment / NASA Greenhouse Effect Detection Expriment 1992 - Disc 2.iso / software / dos / cdf22pc / src / lib / cdflibx.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-02-13  |  37.7 KB  |  1,329 lines

  1. /******************************************************************************
  2. *
  3. *  NSSDC/CDF                      CDF library auxiliary functions.
  4. *
  5. *  Version 1.0, 14-Feb-92, ST Systems (STX)
  6. *
  7. *  Modification history:
  8. *
  9. *   V1.0  14-Feb-92, J Love    Original version.  These functions were taken
  10. *                out of `cdflib.c'.
  11. *
  12. ******************************************************************************/
  13.  
  14. #include "cdflib.h"
  15.  
  16. /******************************************************************************
  17. * Determine disposition of status.
  18. ******************************************************************************/
  19.  
  20. void STATUSdispX (Tstatus, Pstatus)
  21. CDFstatus Tstatus;
  22. CDFstatus *Pstatus;
  23. {
  24. if (Tstatus != CDF_OK)
  25.   if (Tstatus > CDF_OK) {
  26.     if (*Pstatus >= CDF_OK) *Pstatus = Tstatus;
  27.   }
  28.   else
  29.     *Pstatus = Tstatus;
  30. return;
  31. }
  32.  
  33.  
  34. /******************************************************************************
  35. * Do a STRing CoMPare Ignoring any Trailing Blanks.
  36. ******************************************************************************/
  37.  
  38. int strcmpITB (string1, string2)
  39. /*const*/ char *string1;
  40. /*const*/ char *string2;
  41. {
  42. size_t len1, len2;
  43.  
  44. for (len1 = strlen(string1); len1 > 0 && string1[len1 - 1] == ' '; len1--);
  45. for (len2 = strlen(string2); len2 > 0 && string2[len2 - 1] == ' '; len2--);
  46.  
  47. if (len1 == len2)
  48.   return strncmp (string1, string2, len1);
  49. else
  50.   return strcmp (string1, string2);
  51.  
  52. }
  53.  
  54. /******************************************************************************
  55. *  Free a CDFid's dynamically allocated memory.
  56. ******************************************************************************/
  57.  
  58. void Free_CDFid (CDF)
  59. struct cdfSTRUCT *CDF;
  60. {
  61. void            *ptr;
  62. struct varSTRUCT    *Var;
  63. struct vixSTRUCT    *Vix;
  64. struct attrSTRUCT    *Attr;
  65. struct entrySTRUCT    *Entry; 
  66.  
  67. Attr = CDF->attrHead;    /* may be NULL if no attributes */
  68.  
  69. while (Attr != NULL) {
  70.    Entry = Attr->entryHead;    /* may be NULL if no entries */
  71.  
  72.    while (Entry != NULL) {
  73.       if (Entry->AEDR.Value != NULL) free (Entry->AEDR.Value);
  74.                         /* if an entry cannot exist
  75.                            without a value, checking
  76.                            first isn't necessary */
  77.       ptr = (void *) Entry;
  78.       Entry = Entry->entryNext;
  79.       free (ptr);
  80.    }
  81.  
  82.    ptr = (void *) Attr;
  83.    Attr = Attr->attrNext;
  84.    free (ptr);
  85. }
  86.  
  87. Var = CDF->varHead;
  88. while (Var != NULL) {
  89.   if (Var->products != NULL) free (Var->products);
  90.   if (Var->hypIndices != NULL) free (Var->hypIndices);
  91.   if (Var->hypProducts != NULL) free (Var->hypProducts);
  92.   if (Var->hypTops != NULL) free (Var->hypTops);
  93.   if (Var->VDR.DimVarys != NULL) free (Var->VDR.DimVarys);
  94.   if (Var->VDR.FillValue != NULL) free (Var->VDR.FillValue);
  95.  
  96.   Vix = Var->vixHead;
  97.   while (Vix != NULL) {
  98.     ptr = (void *) Vix;
  99.     Vix = Vix->vixNext;
  100.     free (ptr);
  101.   }
  102.  
  103.   ptr = (void *) Var;
  104.   Var = Var->varNext;
  105.   free (ptr);
  106. }
  107.  
  108. if (CDF->indices != NULL) free (CDF->indices);
  109. if (CDF->counts != NULL) free (CDF->counts);
  110. if (CDF->intervals != NULL) free (CDF->intervals);
  111.  
  112. if (CDF->GDR.DimSizes != NULL) free (CDF->GDR.DimSizes);
  113.  
  114. free (CDF);
  115.  
  116. return;
  117. }
  118.  
  119. /******************************************************************************
  120. *  Close a variable vector file to free a file pointer.  The "current" variable
  121. * of a CDF could be the one being closed.  Note that if a CDF is SINGLE file,
  122. * each variable's 'status' will be NO_VAR_FILE (so that variable will not be
  123. * considered for closing).
  124. ******************************************************************************/
  125.  
  126. CDFstatus CloseLRUvar ()
  127. {
  128. CDFid id;
  129. struct varSTRUCT *Var;
  130. struct varSTRUCT *oldestVar = NULL;
  131. long oldest_access = _CDFpseudo_clock;
  132. int stat;
  133.  
  134. for (id = 0; id < CDF_MAX_CDFS; id++)
  135.    if (_CDFs[id] != NULL) {
  136.      Var = _CDFs[id]->varHead;
  137.      while (Var != NULL) {
  138.        if (Var->status == VAR_OPENED)            /* must be MULTI */
  139.      if (Var->accessed_at < oldest_access) {
  140.        oldest_access = Var->accessed_at;
  141.        oldestVar = Var;
  142.      }
  143.        Var = Var->varNext;
  144.      }
  145.    }
  146.  
  147. if (oldestVar != NULL) {
  148.    stat = Close (oldestVar->fp);
  149.    if (stat == EOF) return VAR_CLOSE_ERROR;
  150.    oldestVar->status = VAR_CLOSED;
  151. }
  152.  
  153. return CDF_OK;
  154. }
  155.  
  156.  
  157. /******************************************************************************
  158. * Open a file (closing a variable file if necessary).
  159. ******************************************************************************/
  160.  
  161. File *OpenFile (filename, a_mode)
  162. /*const*/ char *filename;
  163. /*const*/ char *a_mode;        /* access mode */
  164. {
  165. File *fp;
  166. CDFstatus Tstatus;    /* temporary status */
  167.  
  168. #if VIO_FOR_STREAM
  169. long n_buffers;        /* number of CACHE buffers (if VIO) */
  170. #endif
  171.  
  172. #if VIO_FOR_STREAM
  173. if (strstr(filename,".v") != NULL)
  174.   n_buffers = nCACHE_BUFFERs_Vnn;
  175. else
  176.   if (strstr(filename,".cdf") != NULL)
  177.     n_buffers = nCACHE_BUFFERs_CDF;
  178.   else
  179.     if (strstr(filename,".cdh") != NULL)
  180.       n_buffers = nCACHE_BUFFERs_CDH;
  181.     else
  182.       n_buffers = 0;
  183. #endif
  184.  
  185. #if VIO_FOR_STREAM
  186. fp = Open (filename, a_mode, n_buffers);
  187. #else
  188. fp = Open (filename, a_mode);
  189. #endif
  190.  
  191. if (fp == NULL) {
  192.   Tstatus = CloseLRUvar ();
  193.   if (Tstatus < CDF_WARN)
  194.     fp = NULL;
  195.   else
  196. #if VIO_FOR_STREAM
  197.     fp = Open (filename, a_mode, n_buffers);            /* try again */
  198. #else
  199.     fp = Open (filename, a_mode);                /* try again */
  200. #endif
  201. }
  202. return fp;
  203. }
  204.  
  205.  
  206. /******************************************************************************
  207. *  Calculate parameters needed to access a variable.
  208. ******************************************************************************/
  209.  
  210. void calcVarParms (CDF, Var)
  211. struct cdfSTRUCT *CDF;
  212. struct varSTRUCT *Var;
  213. {
  214. int i, j;
  215.  
  216. /* Compute product array */
  217.  
  218. if (bitclr(CDF->CDR.Flags,CDF_MAJORITY_BIT)) { /* COLUMN MAJOR */
  219.    for (i = 0; i < CDF->GDR.NumDims; i++) {
  220.       Var->products[i] = 1;
  221.       for (j = 0; j < i; j++)
  222.      if (Var->VDR.DimVarys[j])
  223.        Var->products[i] *= CDF->GDR.DimSizes[j];
  224.    }
  225. }
  226. else {  /* ROW MAJOR */
  227.    for (i = 0; i < CDF->GDR.NumDims; i++) {
  228.       Var->products[i] = 1;
  229.       for (j = i+1; j < CDF->GDR.NumDims; j++)
  230.      if (Var->VDR.DimVarys[j])
  231.        Var->products[i] *= CDF->GDR.DimSizes[j];
  232.    }
  233. }
  234.  
  235. Var->NvalueBytes = Var->VDR.NumElem * _CDFelemSizes[Var->VDR.DataType];
  236.  
  237. Var->NphyRecValues = 1;
  238. Var->NvirtRecValues = 1;
  239.  
  240. for (i = 0; i < CDF->GDR.NumDims; i++) {
  241.    Var->NvirtRecValues *= CDF->GDR.DimSizes[i];
  242.    if (Var->VDR.DimVarys[i]) Var->NphyRecValues *= CDF->GDR.DimSizes[i];
  243. }
  244.  
  245. Var->NphyRecBytes = Var->NphyRecValues * Var->NvalueBytes;
  246. Var->NvirtRecBytes = Var->NvirtRecValues * Var->NvalueBytes;
  247.  
  248. if (bitset(CDF->CDR.Flags,CDF_FORMAT_BIT))
  249.   Var->defaultNextendRecs =
  250.         Maximum((MIN_nEXTEND_BYTES_single-1)/Var->NphyRecBytes + 1,
  251.             MIN_nEXTEND_RECS_single);
  252. else
  253.   Var->defaultNextendRecs = MIN_nEXTEND_RECS_multi;
  254.  
  255. return;
  256. }
  257.  
  258. /******************************************************************************
  259. *  Open a variable (file) for access.  Only called if MULTI file.
  260. ******************************************************************************/
  261.  
  262. CDFstatus OpenVar (CDF, Var)
  263. struct cdfSTRUCT *CDF;
  264. struct varSTRUCT *Var;
  265. {
  266. char tmp_filename[CDF_PATHNAME_LEN+6+1];    /* +6+1 for .Vnnnn and
  267.                            NUL-terminator */
  268. #if defined(unix) | defined(__MSDOS__)
  269. sprintf (tmp_filename, "%s.v%d", CDF->filename, Var->VDR.Num);
  270. #endif
  271.  
  272. #if defined(vms)
  273. if (CDF->CDR.Version == 1)
  274.   sprintf (tmp_filename, "%s.v%02d", CDF->filename, Var->VDR.Num + 1);
  275. else
  276.   sprintf (tmp_filename, "%s.v%d", CDF->filename, Var->VDR.Num);
  277. #endif
  278.  
  279. if (CDF->status == CDF_READ_WRITE) {
  280. #if defined(vms) | defined(__MSDOS__)
  281.    Var->fp = OpenFile (tmp_filename,"r+b");
  282. #endif
  283. #if defined(unix)
  284.    Var->fp = OpenFile (tmp_filename,"r+");
  285. #endif
  286.    if (Var->fp == NULL) return VAR_OPEN_ERROR;
  287. }
  288. else {  /* READ ONLY */
  289. #if defined(vms) | defined(__MSDOS__)
  290.    Var->fp = OpenFile (tmp_filename,"rb");
  291. #endif
  292. #if defined(unix)
  293.    Var->fp = OpenFile (tmp_filename,"r");
  294. #endif
  295.    if (Var->fp == NULL) return VAR_OPEN_ERROR;
  296. }
  297.  
  298. Var->status = VAR_OPENED;
  299.  
  300. return CDF_OK;
  301. }
  302.  
  303. /******************************************************************************
  304. *  Fill the records for a variable.
  305. ******************************************************************************/
  306.  
  307. CDFstatus FillRecords (CDF, Var, offset, Nrecs)
  308. struct cdfSTRUCT *CDF;
  309. struct varSTRUCT *Var;
  310. long offset;
  311. long Nrecs;
  312. {
  313. void *value;
  314. long Nbytes;
  315. size_t N;
  316. void *fill;
  317. long elemN;    /* Element number within a value. */
  318. long Boffset;    /* Byte offset within buffer. */
  319. long recN;    /* Record number. */
  320. long valueN;    /* Value number within a physical record. */
  321. int  stat;
  322.  
  323. /******************************************************************************
  324. * Determine fill value.
  325. ******************************************************************************/
  326.  
  327. if (bitset(Var->VDR.Flags,VAR_FILLVALUE_BIT))
  328.   value = Var->VDR.FillValue;
  329. else {
  330.   value = (void *) malloc (Var->NvalueBytes);
  331.   if (value == NULL) return BAD_MALLOC;
  332.   for (elemN = 0; elemN < Var->VDR.NumElem; elemN++) {
  333.      memmove ((Byte *) value + elemN*_CDFelemSizes[Var->VDR.DataType],
  334.           _CDFdefaultFillValues[Var->VDR.DataType],
  335.           _CDFelemSizes[Var->VDR.DataType]);
  336.   }
  337. }
  338.  
  339. stat = Seek (Var->fp, offset, SEEK_SET);
  340. if (stat == EOF) {
  341.   /* CLEAN UP */
  342.   return VAR_WRITE_ERROR;
  343. }
  344.  
  345. /******************************************************************************
  346. * Try to do it all at once.
  347. ******************************************************************************/
  348.  
  349. Nbytes = Nrecs * Var->NphyRecBytes;
  350.  
  351. #if defined(__MSDOS__)
  352. if (Nbytes < (long) 65536) {
  353. #endif
  354.   fill = (void *) malloc (Nbytes);
  355.   if (fill != NULL) {
  356.     for (Boffset = 0; Boffset < Nbytes; Boffset += Var->NvalueBytes)
  357.        memmove ((Byte *) fill + Boffset, value, Var->NvalueBytes);
  358.  
  359. #if defined(sun) | defined(MIPSEB) | defined(IBMRS) | defined(HP)
  360.     /* Do nothing. */
  361. #endif
  362.  
  363. #if defined(vax) | defined(MIPSEL) | defined(__IBMPC__)
  364.     if (CDF->CDR.Encoding == NETWORK_ENCODING)
  365.       xdr_encode (Var->VDR.DataType, Nbytes / _CDFelemSizes[Var->VDR.DataType],
  366.           fill, fill);
  367. #endif
  368.  
  369.     N = putbytes (Nbytes, fill, Var->fp);
  370.     if (N != Nbytes) {
  371.       if (value != Var->VDR.FillValue) free (value);
  372.       free (fill);
  373.       return VAR_WRITE_ERROR;
  374.     }
  375.     if (value != Var->VDR.FillValue) free (value);
  376.     free (fill);
  377.     return CDF_OK;
  378.   }
  379. #if defined(__MSDOS__)
  380. }
  381. #endif
  382.  
  383. /******************************************************************************
  384. * That didn't work (no return yet), try one record at a time.
  385. ******************************************************************************/
  386.  
  387. Nbytes = Var->NphyRecBytes;
  388.  
  389. #if defined(__MSDOS__)
  390. if (Nbytes < (long) 65536) {
  391. #endif
  392.   fill = (void *) malloc (Nbytes);
  393.   if (fill != NULL) {
  394.     for (Boffset = 0; Boffset < Nbytes; Boffset += Var->NvalueBytes)
  395.        memmove ((Byte *) fill + Boffset, value, Var->NvalueBytes);
  396.  
  397. #if defined(sun) | defined(MIPSEB) | defined(IBMRS) | defined(HP)
  398.     /* Do nothing. */
  399. #endif
  400.  
  401. #if defined(vax) | defined(MIPSEL) | defined(__IBMPC__)
  402.     xdr_encode (Var->VDR.DataType, Nbytes / _CDFelemSizes[Var->VDR.DataType],
  403.         fill, fill);
  404. #endif
  405.  
  406.     for (recN = 0; recN < Nrecs; recN++) {
  407.        N = putbytes (Nbytes, fill, Var->fp);
  408.        if (N != Nbytes) {
  409.      if (value != Var->VDR.FillValue) free (value);
  410.      free (fill);
  411.      return VAR_WRITE_ERROR;
  412.        }
  413.     }
  414.     if (value != Var->VDR.FillValue) free (value);
  415.     free (fill);
  416.     return CDF_OK;
  417.   }
  418. #if defined(__MSDOS__)
  419. }
  420. #endif
  421.  
  422. /******************************************************************************
  423. * That didn't work (no return yet), try one value at a time.
  424. ******************************************************************************/
  425.  
  426. Nbytes = Var->NvalueBytes;
  427.  
  428. fill = (void *) malloc (Nbytes);
  429. if (fill != NULL) {
  430.   memmove (fill, value, Var->NvalueBytes);
  431.  
  432. #if defined(sun) | defined(MIPSEB) | defined(IBMRS) | defined(HP)
  433.   /* Do nothing. */
  434. #endif
  435.  
  436. #if defined(vax) | defined(MIPSEL) | defined(__IBMPC__)
  437.   xdr_encode (Var->VDR.DataType, Var->VDR.NumElem, fill, fill);
  438. #endif
  439.  
  440.   for (recN = 0; recN < Nrecs; recN++) {
  441.      for (valueN = 0; valueN < Var->NphyRecValues; valueN++) {
  442.         N = putbytes (Nbytes, fill, Var->fp);
  443.         if (N != Nbytes) {
  444.           if (value != Var->VDR.FillValue) free (value);
  445.           free (fill);
  446.           return VAR_WRITE_ERROR;
  447.         }
  448.      }
  449.   }
  450.   if (value != Var->VDR.FillValue) free (value);
  451.   free (fill);
  452.   return CDF_OK;
  453. }
  454.  
  455. /******************************************************************************
  456. * That didn't work, there must be something seriously wrong.
  457. ******************************************************************************/
  458.  
  459. return BAD_MALLOC;
  460. }
  461.  
  462.  
  463. /******************************************************************************
  464. *  Allocate variable records.
  465. ******************************************************************************/
  466.  
  467. CDFstatus AllocateRecords (CDF, Var, neededRecNum, override)
  468. struct cdfSTRUCT *CDF;
  469. struct varSTRUCT *Var;
  470. long neededRecNum;
  471. Boolean override;      /* if TRUE, override minimum number of extend records */
  472. {
  473. long offset;
  474. long lastRecAllocated;
  475. long NneededRecs;
  476. long Nbytes;
  477. long Nrecs;
  478. Int32 RecordSize;
  479. Int32 RecordType;
  480. struct vixSTRUCT *Vix;
  481. struct vixSTRUCT *ntlVix;    /* next-to-last Vix */
  482. CDFstatus Pstatus = CDF_OK;
  483. CDFstatus Tstatus;
  484. long i;
  485.  
  486. /******************************************************************************
  487. * Check if MULTI file...
  488. ******************************************************************************/
  489.  
  490. if (bitclr(CDF->CDR.Flags,CDF_FORMAT_BIT)) {
  491.   if (override)
  492.     NneededRecs = neededRecNum - Var->VDR.MaxRec;
  493.   else
  494.     NneededRecs = Maximum(neededRecNum - Var->VDR.MaxRec,
  495.               (Var->VDR.NextendRecs == 0 ?
  496.                  Var->defaultNextendRecs : Var->VDR.NextendRecs));
  497.   offset = (Var->VDR.MaxRec + 1) * Var->NphyRecBytes;
  498.   Tstatus = FillRecords (CDF, Var, offset, NneededRecs);
  499.   STATUSdisp (Tstatus, Pstatus);
  500.   return Pstatus;
  501. }
  502.  
  503. /******************************************************************************
  504. * Not MULTI file, must be SINGLE file.  First check if the needed record is
  505. * already allocated (but not used yet)...
  506. ******************************************************************************/
  507.  
  508. if (Var->vixTail != NULL) {
  509.   Vix = Var->vixTail;
  510.   if (Vix->VXR.FirstRec[Vix->VXR.NusedEntries-1] <= neededRecNum &&
  511.       neededRecNum <= Vix->VXR.LastRec[Vix->VXR.NusedEntries-1])
  512.     return Pstatus;
  513. }
  514.  
  515. /******************************************************************************
  516. * Not allocated yet, allocate to at least the needed record.
  517. ******************************************************************************/
  518.  
  519. if (Var->vixTail == NULL) {
  520.   /************************************************************************
  521.   * NO records yet for the variable.
  522.   ************************************************************************/
  523.  
  524.   Vix = (struct vixSTRUCT *) malloc (sizeof(struct vixSTRUCT));
  525.   if (Vix == NULL) return BAD_MALLOC;
  526.   Var->vixHead = Vix;
  527.   Var->vixTail = Vix;
  528.   Vix->vixNext = (struct vixSTRUCT *) NULL;
  529.  
  530.   /*** set up VXR ***/
  531.  
  532.   Vix->VXRoffset = CDF->GDR.eof;
  533.  
  534.   Vix->VXR.RecordSize = VXR_BASE_SIZE + (3 * N_VXR_ENTRIES * sizeof(Int32));
  535.   Vix->VXR.RecordType = VXR_;
  536.   Vix->VXR.VXRnext = 0;
  537.   Vix->VXR.Nentries = N_VXR_ENTRIES;
  538.   Vix->VXR.NusedEntries = 0;
  539.  
  540.   Nbytes = N_VXR_ENTRIES * sizeof(Int32);
  541.   Vix->VXR.FirstRec = (Int32 *) malloc (Nbytes);
  542.   if (Vix->VXR.FirstRec == NULL) return BAD_MALLOC;
  543.   Vix->VXR.LastRec = (Int32 *) malloc (Nbytes);
  544.   if (Vix->VXR.LastRec == NULL) return BAD_MALLOC;
  545.   Vix->VXR.VVRoffset = (Int32 *) malloc (Nbytes);
  546.   if (Vix->VXR.VVRoffset == NULL) return BAD_MALLOC;
  547.  
  548.   for (i = 0; i < N_VXR_ENTRIES; i++) {  /* start entry field at -1 */
  549.      Vix->VXR.FirstRec[i] = -1;
  550.      Vix->VXR.LastRec[i] = -1;
  551.      Vix->VXR.VVRoffset[i] = -1;
  552.   }
  553.  
  554.   CDF->GDR.eof += Vix->VXR.RecordSize;
  555.  
  556.   /*** point VDR to this VXR ***/
  557.  
  558.   Var->VDR.VXRhead = Vix->VXRoffset;
  559.   Var->VDR.VXRtail = Vix->VXRoffset;
  560.  
  561.   /*** create VVR ***/
  562.  
  563.   if (override)
  564.     Nrecs = neededRecNum + 1;
  565.   else
  566.     Nrecs = Maximum(neededRecNum + 1,
  567.             (Var->VDR.NextendRecs == 0 ?
  568.             Var->defaultNextendRecs : Var->VDR.NextendRecs));
  569.  
  570.   offset = CDF->GDR.eof;
  571.  
  572.   RecordSize = VVR_BASE_SIZE + (Nrecs * Var->NphyRecBytes);
  573.   RecordType = VVR_;
  574.  
  575.   Seek (CDF->fp, offset, SEEK_SET);
  576.   putint32 (CDF->fp, RecordSize);
  577.   putint32 (CDF->fp, RecordType);
  578.  
  579.   Tstatus = FillRecords (CDF, Var, offset + VVR_BASE_SIZE, Nrecs);
  580.   STATUSdisp (Tstatus, Pstatus);
  581.  
  582.   CDF->GDR.eof += RecordSize;
  583.  
  584.   Vix->VXR.FirstRec[0] = 0;
  585.   Vix->VXR.LastRec[0] = Nrecs - 1;
  586.   Vix->VXR.VVRoffset[0] = offset;
  587.   Vix->VXR.NusedEntries = 1;
  588. }
  589. else {
  590.   /************************************************************************
  591.   * Already some records for the variable.
  592.   ************************************************************************/
  593.  
  594.   Vix = Var->vixTail;
  595.   lastRecAllocated = Vix->VXR.LastRec[Vix->VXR.NusedEntries-1];
  596.  
  597.   if (override)
  598.     Nrecs = neededRecNum - lastRecAllocated;
  599.   else
  600.     Nrecs = Maximum(neededRecNum - lastRecAllocated,
  601.             (Var->VDR.NextendRecs == 0 ?
  602.                 Var->defaultNextendRecs : Var->VDR.NextendRecs));
  603.  
  604.   /************************************************************************
  605.   * First check if the last VVR can be extended (only if it is the last
  606.   * internal record in the CDF).
  607.   ************************************************************************/
  608.  
  609.   offset = Vix->VXR.VVRoffset[Vix->VXR.NusedEntries - 1];
  610.   Seek (CDF->fp, offset, SEEK_SET);
  611.   getint32 (CDF->fp, RecordSize);
  612.  
  613.   if (offset + RecordSize == CDF->GDR.eof) {
  614.     RecordSize += Nrecs * Var->NphyRecBytes;
  615.     Seek (CDF->fp, offset, SEEK_SET);
  616.     putint32 (CDF->fp, RecordSize);
  617.  
  618.     Tstatus = FillRecords (CDF, Var, CDF->GDR.eof, Nrecs);
  619.     STATUSdisp (Tstatus, Pstatus);
  620.  
  621.     CDF->GDR.eof += Nrecs * Var->NphyRecBytes;
  622.     Vix->VXR.LastRec[Vix->VXR.NusedEntries - 1] += Nrecs;
  623.  
  624.     return Pstatus;
  625.   }
  626.  
  627.   /************************************************************************
  628.   * Can't extend last VVR, create another VVR.
  629.   ************************************************************************/
  630.  
  631.   RecordSize = VVR_BASE_SIZE + (Nrecs * Var->NphyRecBytes);
  632.   RecordType = VVR_;
  633.  
  634.   offset = CDF->GDR.eof;
  635.  
  636.   Seek (CDF->fp, offset, SEEK_SET);
  637.   putint32 (CDF->fp, RecordSize);
  638.   putint32 (CDF->fp, RecordType);
  639.  
  640.   Tstatus = FillRecords (CDF, Var, offset + VVR_BASE_SIZE, Nrecs);
  641.   STATUSdisp (Tstatus, Pstatus);
  642.  
  643.   CDF->GDR.eof += RecordSize;
  644.  
  645.   /*** add entry to last VXR (or create new VXR if last VXR is full) ***/
  646.  
  647.   if (Vix->VXR.NusedEntries < Vix->VXR.Nentries) {
  648.     Vix->VXR.FirstRec[Vix->VXR.NusedEntries] = lastRecAllocated + 1;
  649.     Vix->VXR.LastRec[Vix->VXR.NusedEntries] = lastRecAllocated + Nrecs;
  650.     Vix->VXR.VVRoffset[Vix->VXR.NusedEntries] = offset;
  651.     Vix->VXR.NusedEntries++;
  652.   }
  653.   else {  /* create a new VXR */
  654.     ntlVix = Vix;
  655.     Vix = (struct vixSTRUCT *) malloc (sizeof(struct vixSTRUCT));
  656.     if (Vix == NULL) return BAD_MALLOC;
  657.     Var->vixTail->vixNext = Vix;
  658.     Var->vixTail = Vix;
  659.     Vix->vixNext = (struct vixSTRUCT *) NULL;
  660.  
  661.     /*** set up VXR ***/
  662.  
  663.     Vix->VXRoffset = CDF->GDR.eof;
  664.  
  665.     Vix->VXR.RecordSize = VXR_BASE_SIZE + (3 * N_VXR_ENTRIES * sizeof(Int32));
  666.     Vix->VXR.RecordType = VXR_;
  667.     Vix->VXR.VXRnext = 0;
  668.     Vix->VXR.Nentries = N_VXR_ENTRIES;
  669.     Vix->VXR.NusedEntries = 0;
  670.  
  671.     Nbytes = N_VXR_ENTRIES * sizeof(Int32);
  672.     Vix->VXR.FirstRec = (Int32 *) malloc (Nbytes);
  673.     if (Vix->VXR.FirstRec == NULL) return BAD_MALLOC;
  674.     Vix->VXR.LastRec = (Int32 *) malloc (Nbytes);
  675.     if (Vix->VXR.LastRec == NULL) return BAD_MALLOC;
  676.     Vix->VXR.VVRoffset = (Int32 *) malloc (Nbytes);
  677.     if (Vix->VXR.VVRoffset == NULL) return BAD_MALLOC;
  678.  
  679.     for (i = 0; i < N_VXR_ENTRIES; i++) {    /* start each field at -1 */
  680.        Vix->VXR.FirstRec[i] = -1;
  681.        Vix->VXR.LastRec[i] = -1;
  682.        Vix->VXR.VVRoffset[i] = -1;
  683.     }
  684.  
  685.     CDF->GDR.eof += Vix->VXR.RecordSize;
  686.  
  687.     /*** point next-to-last VXR and VDR to this VXR ***/
  688.  
  689.     ntlVix->VXR.VXRnext = Vix->VXRoffset;
  690.     Var->VDR.VXRtail = Vix->VXRoffset;
  691.  
  692.     /*** add entry to new VXR ***/
  693.  
  694.     Vix->VXR.FirstRec[0] = lastRecAllocated + 1;
  695.     Vix->VXR.LastRec[0] = lastRecAllocated + Nrecs;
  696.     Vix->VXR.VVRoffset[0] = offset;
  697.     Vix->VXR.NusedEntries = 1;
  698.   }
  699. }
  700. return Pstatus;
  701. }
  702.  
  703.  
  704. /******************************************************************************
  705. *  Calculate the EOF (byte offset) for a V2.0 CDF.
  706. ******************************************************************************/
  707.  
  708. void calc_V20_eof (CDF)
  709. struct cdfSTRUCT *CDF;
  710. {
  711. struct varSTRUCT   *Var;
  712. struct attrSTRUCT  *Attr;
  713. struct entrySTRUCT *Entry;
  714. long EoF = 0;
  715.  
  716. if (CDF->CDRoffset + CDF->CDR.RecordSize > EoF)
  717.   EoF = CDF->CDRoffset + CDF->CDR.RecordSize;
  718.  
  719. if (CDF->GDRoffset + CDF->GDR.RecordSize > EoF)
  720.   EoF = CDF->GDRoffset + CDF->GDR.RecordSize;
  721.  
  722. Var = CDF->varHead;
  723. while (Var != NULL) {
  724.   if (Var->VDRoffset + Var->VDR.RecordSize > EoF)
  725.     EoF = Var->VDRoffset + Var->VDR.RecordSize;
  726.   Var = Var->varNext;
  727. }
  728.  
  729. Attr = CDF->attrHead;
  730. while (Attr != NULL) {
  731.    if (Attr->ADRoffset + Attr->ADR.RecordSize > EoF)
  732.      EoF = Attr->ADRoffset + Attr->ADR.RecordSize;
  733.  
  734.    Entry = Attr->entryHead;
  735.    while (Entry != NULL) {
  736.       if (Entry->AEDRoffset + Entry->AEDR.RecordSize > EoF)
  737.         EoF = Entry->AEDRoffset + Entry->AEDR.RecordSize;
  738.  
  739.       Entry = Entry->entryNext;
  740.    }
  741.  
  742.    Attr = Attr->attrNext;
  743. }
  744.  
  745. CDF->GDR.eof = EoF;
  746. return;
  747. }
  748.  
  749. /******************************************************************************
  750. *  Close the open files of the specified CDF.
  751. ******************************************************************************/
  752.  
  753. CDFstatus CloseCDFfiles (CDF)
  754. struct cdfSTRUCT *CDF;
  755. {
  756. CDFstatus Pstatus = CDF_OK;    /* pending status */
  757. CDFstatus Tstatus;        /* temporary status */
  758. int stat;
  759. struct varSTRUCT *Var;
  760.  
  761. if (CDF->status == CDF_READ_WRITE && CDF->CDR.Version == 2) {
  762.   Tstatus = write_V2_header (CDF);
  763.   STATUSdisp (Tstatus, Pstatus);
  764. }
  765.  
  766. stat = Close (CDF->fp);
  767. if (stat == EOF) return CDF_CLOSE_ERROR;
  768.  
  769. CDF->status = CDF_CLOSED;
  770.  
  771. if (bitclr(CDF->CDR.Flags,CDF_FORMAT_BIT)) {    /* if MULTI file */
  772.   Var = CDF->varHead;
  773.   while (Var != NULL) {
  774.     if (Var->status == VAR_OPENED) {
  775.       stat = Close (Var->fp);
  776.       if (stat == EOF) return VAR_CLOSE_ERROR;
  777.       Var->status = VAR_CLOSED;
  778.     }
  779.     Var = Var->varNext;
  780.   }
  781. }
  782.  
  783. return Pstatus;
  784. }
  785.  
  786. /******************************************************************************
  787. * Close and then reopen a CDF for read/write access (it was opened with
  788. * read-only access initially).
  789. ******************************************************************************/
  790.  
  791. CDFstatus ReopenCDFforWrite (CDF)
  792. struct cdfSTRUCT *CDF;
  793. {
  794. CDFstatus Pstatus = CDF_OK;        /* pending status */
  795. CDFstatus Tstatus;            /* temporary status */
  796. char openname[CDF_PATHNAME_LEN+4+1];    /* +4+1 for ".cdf" and NUL */
  797. struct varSTRUCT *Var;
  798.  
  799. Tstatus = CloseCDFfiles (CDF);
  800. STATUSdisp (Tstatus, Pstatus);
  801.  
  802. strcpy (openname, CDF->filename);
  803. strcat (openname, ".cdf");
  804.  
  805. #if defined(vms) | defined(__MSDOS__)
  806. CDF->fp = OpenFile (openname, "r+b");
  807. #endif
  808. #if defined(unix)
  809. CDF->fp = OpenFile (openname, "r+");
  810. #endif
  811. if (CDF->fp == NULL) return NO_WRITE_ACCESS;
  812.  
  813. CDF->status = CDF_READ_WRITE;
  814.  
  815. /** if SINGLE, point the variable file pointers to the .CDF file pointer **/
  816.  
  817. if (bitset(CDF->CDR.Flags,CDF_FORMAT_BIT)) {
  818.   Var = CDF->varHead;
  819.   while (Var != NULL) {
  820.     Var->fp = CDF->fp;
  821.     Var = Var->varNext;
  822.   }
  823. }
  824.  
  825. return Pstatus;
  826. }
  827.  
  828.  
  829. /******************************************************************************
  830. *  Increment to next strip for Hyper function (ROW major CDF).
  831. ******************************************************************************/
  832.  
  833. void incr_hypIndices_ROW (hypIndices, idim, indices, intervals, hypTops,
  834.               dimVary, complete, physical, updim)
  835. long hypIndices[];
  836. long idim;
  837. long indices[];
  838. long intervals[];
  839. long hypTops[];
  840. long dimVary[];
  841. Boolean *complete;    /* Assumed to be set FALSE by caller. */
  842. Boolean *physical;
  843. long *updim;        /* Assumed to have proper value from last call. */
  844. {
  845. long dim_n;
  846. long startdim;
  847.  
  848. if ( ! dimVary[*updim]) {
  849.    if (hypIndices[*updim] < hypTops[*updim]) {
  850.       hypIndices[*updim] += intervals[*updim];
  851.       *physical = FALSE;
  852.       return;
  853.    }
  854.    else
  855.       startdim = *updim;
  856. }
  857. else
  858.    startdim = idim;
  859.  
  860. for (dim_n = startdim; dim_n >= 0; dim_n--)
  861.    if (hypIndices[dim_n] < hypTops[dim_n]) {
  862.       *updim = dim_n;
  863.       hypIndices[*updim] += intervals[*updim];
  864.  
  865.       if (dimVary[*updim])
  866.      *physical = TRUE;
  867.        else
  868.      *physical = FALSE;
  869.  
  870.       return;
  871.    }
  872.    else
  873.       hypIndices[dim_n] = indices[dim_n];
  874.  
  875. *complete = TRUE;
  876. return;
  877.  
  878. }
  879.  
  880. /******************************************************************************
  881. *  Increment to next strip for Hyper function (COLumn major CDF).
  882. ******************************************************************************/
  883.  
  884. void incr_hypIndices_COL (rank, hypIndices, idim, indices, intervals, hypTops,
  885.               dimVary, complete, physical, updim)
  886. long rank;
  887. long hypIndices[];
  888. long idim;
  889. long indices[];
  890. long intervals[];
  891. long hypTops[];
  892. long dimVary[];
  893. Boolean *complete;    /* Assumed to be set FALSE be caller. */
  894. Boolean *physical;
  895. long *updim;        /* Assumed to have proper value from last call. */
  896. {
  897. long dim_n;
  898. long startdim;
  899.  
  900. if ( ! dimVary[*updim]) {
  901.    if (hypIndices[*updim] < hypTops[*updim]) {
  902.       hypIndices[*updim] += intervals[*updim];
  903.       *physical = FALSE;
  904.       return;
  905.    }
  906.    else
  907.       startdim = *updim;
  908. }
  909. else
  910.    startdim = idim;
  911.  
  912. for (dim_n = startdim; dim_n < rank; dim_n++)
  913.    if (hypIndices[dim_n] < hypTops[dim_n]) {
  914.       *updim = dim_n;
  915.       hypIndices[*updim] += intervals[*updim];
  916.  
  917.       if (dimVary[*updim])
  918.     *physical = TRUE;
  919.       else
  920.     *physical = FALSE;
  921.  
  922.       return;
  923.    }
  924.    else
  925.       hypIndices[dim_n] = indices[dim_n];
  926.  
  927. *complete = TRUE;
  928. return;
  929. }
  930.  
  931. /******************************************************************************
  932. *  Get bytes (strip) for HyperGet function.  If on IBM PC, assumed that
  933. * 'striplen' is not greater than 64Kb.
  934. ******************************************************************************/
  935.  
  936. CDFstatus HyperGetBytes (Var, offset, striplen, value)
  937. struct varSTRUCT *Var;
  938. long offset;
  939. long striplen;
  940. void *value;
  941. {
  942. size_t N;
  943.  
  944. Seek (Var->fp, offset, SEEK_SET);
  945. N = getbytes (striplen, value, Var->fp);
  946. if (N != striplen) return VAR_READ_ERROR;
  947.  
  948. DecodeBuffer (_CURcdf->CDR.Encoding, Var->VDR.DataType,
  949.           striplen / _CDFelemSizes[Var->VDR.DataType], value);
  950.  
  951. return CDF_OK;
  952. }
  953.  
  954. /******************************************************************************
  955. *  Put bytes (strip) for HyperPut function.  If on IBM PC, assumed that
  956. * 'striplen' is not greater than 64Kb.
  957. ******************************************************************************/
  958.  
  959. CDFstatus HyperPutBytes (Var, offset, striplen, value)
  960. struct varSTRUCT *Var;
  961. long offset;
  962. long striplen;
  963. void *value;
  964. {
  965. size_t N;
  966.  
  967. Seek (Var->fp, offset, SEEK_SET);
  968.  
  969. #if defined(sun) | defined(MIPSEB) | defined(IBMRS) | defined(HP)
  970. N = putbytes (striplen, value, Var->fp);
  971. if (N != striplen) return VAR_WRITE_ERROR;
  972. #endif
  973.  
  974. #if defined(vax) | defined(MIPSEL) | defined(__IBMPC__)
  975. if (_CURcdf->CDR.Encoding == NETWORK_ENCODING) {
  976.   void *tmpbuffer;
  977.   long numValues, i, vsize;
  978.  
  979.   tmpbuffer = (void *) malloc (striplen);
  980.   if (tmpbuffer != NULL) {
  981.     xdr_encode (Var->VDR.DataType, striplen / _CDFelemSizes[Var->VDR.DataType],
  982.         value, tmpbuffer);
  983.     N = putbytes (striplen, tmpbuffer, Var->fp);
  984.     if (N != striplen) {
  985.       free (tmpbuffer);
  986.       return VAR_WRITE_ERROR;
  987.     }
  988.   }
  989.   else {
  990.     vsize = Var->VDR.NumElem * _CDFelemSizes[Var->VDR.DataType];
  991.     tmpbuffer = (void *) malloc (vsize);
  992.     if (tmpbuffer == NULL) return BAD_MALLOC;
  993.     numValues = striplen / vsize;
  994.     for (i = 0; i < numValues; i++) {
  995.        xdr_encode (Var->VDR.DataType, Var->VDR.NumElem,
  996.            (Byte *) value + i*vsize, tmpbuffer);
  997.        N = putbytes (vsize, tmpbuffer, Var->fp);
  998.        if (N != vsize) {
  999.      free (tmpbuffer);
  1000.      return VAR_WRITE_ERROR;
  1001.        }
  1002.     }
  1003.   }
  1004.   free (tmpbuffer);
  1005. }
  1006. else {    /* host's encoding */
  1007.    N = putbytes (striplen, value, Var->fp);
  1008.    if (N != striplen) return VAR_WRITE_ERROR;
  1009. }
  1010. #endif
  1011.  
  1012. return CDF_OK;
  1013. }
  1014.  
  1015. /******************************************************************************
  1016. *  Perform Hyper function.
  1017. ******************************************************************************/
  1018.  
  1019. CDFstatus HyperAccess (Var, value, row_major, get)
  1020. struct varSTRUCT *Var;
  1021. void *value;
  1022. long row_major;        /* TRUE if row major, FALSE if column major */
  1023. long get;        /* TRUE if hyperGet, FALSE if hyperPut */
  1024. {
  1025. Boolean complete, physical;
  1026. long numDims, dimN, updim;
  1027. long striplen, hypRecSize;
  1028. long recTop, rec_n, movelen;
  1029. long recOffset, offset, indicesOffset;
  1030. long idim;            /* the dimension to increment (all dimensions
  1031.                    above/below it are read/written in their
  1032.                    physical entirety) */
  1033. Boolean one_access_idim;    /* (imaginary) dimension to increment if only
  1034.                    one physical read/write is necessary for
  1035.                    each record */
  1036. Boolean full_contig_records;    /* TRUE if full contiguous records are being
  1037.                    read/written */
  1038. CDFstatus Pstatus = CDF_OK;    /* pending status */
  1039. CDFstatus Tstatus;        /* temporary status */
  1040. long Nelements;
  1041. long Nvalues;
  1042. long valueN;
  1043. long elemN;
  1044.  
  1045. numDims = _CURcdf->GDR.NumDims;
  1046.  
  1047. if (row_major)
  1048.    one_access_idim = -1;
  1049.  else
  1050.    one_access_idim = numDims;
  1051.  
  1052. if (numDims > 0) {
  1053.    if (row_major) {
  1054.       Var->hypProducts[numDims-1] = 1;
  1055.  
  1056.       for (dimN = numDims-2; dimN >= 0; dimN--)
  1057.          Var->hypProducts[dimN] = Var->hypProducts[dimN+1] *
  1058.                    _CURcdf->counts[dimN+1];
  1059.  
  1060.       hypRecSize = (Var->hypProducts[0] * _CURcdf->counts[0]) *
  1061.                             Var->NvalueBytes;
  1062.    }
  1063.    else {
  1064.       Var->hypProducts[0] = 1;
  1065.  
  1066.       for (dimN = 1; dimN < numDims; dimN++)
  1067.          Var->hypProducts[dimN] = Var->hypProducts[dimN-1] *
  1068.                    _CURcdf->counts[dimN-1];
  1069.  
  1070.       hypRecSize = (Var->hypProducts[numDims-1] * _CURcdf->counts[numDims-1]) *
  1071.            Var->NvalueBytes;
  1072.    }
  1073.  
  1074.    for (dimN = 0; dimN < numDims; dimN++)
  1075.       Var->hypTops[dimN] = _CURcdf->indices[dimN] +
  1076.                 (_CURcdf->counts[dimN] - 1) *
  1077.                         _CURcdf->intervals[dimN];
  1078. }
  1079. else
  1080.    hypRecSize = Var->NvalueBytes;
  1081.  
  1082. if (numDims > 0) {
  1083.    full_contig_records = TRUE;
  1084.    if (row_major) {
  1085.       for (idim = numDims-1; idim >= 0; idim--) {
  1086.      if (Var->VDR.DimVarys[idim]) {
  1087.        if (_CURcdf->counts[idim] < _CURcdf->GDR.DimSizes[idim]) {
  1088.          if (_CURcdf->intervals[idim] > 1) {
  1089.            striplen = Var->products[idim] * Var->NvalueBytes;
  1090.          }
  1091.          else {
  1092.            striplen = Var->products[idim] * _CURcdf->counts[idim] *
  1093.                                 Var->NvalueBytes;
  1094.            idim--;
  1095.          }
  1096.          full_contig_records = FALSE;
  1097.          break;
  1098.        }
  1099.      }
  1100.      else {
  1101.        if (_CURcdf->counts[idim] > 1) {
  1102.          striplen = Var->products[idim] * Var->NvalueBytes;
  1103.          full_contig_records = FALSE;
  1104.          break;
  1105.        }
  1106.      }
  1107.       }
  1108.       /*** if loop completed, idim = one_access_idim ***/
  1109.    }
  1110.    else {
  1111.       for (idim = 0; idim < numDims; idim++) {
  1112.      if (Var->VDR.DimVarys[idim]) {
  1113.        if (_CURcdf->counts[idim] < _CURcdf->GDR.DimSizes[idim]) {
  1114.          if (_CURcdf->intervals[idim] > 1) {
  1115.            striplen = Var->products[idim] * Var->NvalueBytes;
  1116.          }
  1117.          else {
  1118.            striplen = Var->products[idim] * _CURcdf->counts[idim] *
  1119.                                 Var->NvalueBytes;
  1120.            idim++;
  1121.          }
  1122.          full_contig_records = FALSE;
  1123.          break;
  1124.        }
  1125.      }
  1126.      else {
  1127.        if (_CURcdf->counts[idim] > 1) {
  1128.          striplen = Var->products[idim] * Var->NvalueBytes;
  1129.          full_contig_records = FALSE;
  1130.          break;
  1131.        }
  1132.      }
  1133.       }
  1134.       /*** if loop completed, idim = one_access_idim ***/
  1135.    }
  1136. }
  1137. else {
  1138.    idim = one_access_idim;
  1139.    full_contig_records = TRUE;
  1140. }
  1141.  
  1142. /******************************************************************************
  1143. * Check if a contiguous strip of records...
  1144. ******************************************************************************/
  1145.  
  1146. if (full_contig_records && _CURcdf->recinterval == 1 &&
  1147.     bitset(Var->VDR.Flags,VAR_RECVARY_BIT) &&
  1148.     bitclr(_CURcdf->CDR.Flags,CDF_FORMAT_BIT)) {
  1149.   if (get) {
  1150.       long lastRec = _CURcdf->recnum + _CURcdf->reccount - 1;
  1151.       long beforeRecs =
  1152.         (_CURcdf->recnum <= Var->VDR.MaxRec ?
  1153.             (lastRec <= Var->VDR.MaxRec ?
  1154.             _CURcdf->reccount :
  1155.              Var->VDR.MaxRec - _CURcdf->recnum + 1) : 0);
  1156.  
  1157.       long afterRecs =
  1158.          (lastRec > Var->VDR.MaxRec ?
  1159.            (_CURcdf->recnum > Var->VDR.MaxRec ?
  1160.          _CURcdf->reccount : lastRec - Var->VDR.MaxRec) : 0);
  1161.  
  1162.       if (beforeRecs > 0) {
  1163.      offset = _CURcdf->recnum * Var->NphyRecBytes;
  1164.      Tstatus = HyperGetBytes (Var, offset, Var->NphyRecBytes * beforeRecs,
  1165.                   value);
  1166.      STATUSdisp (Tstatus, Pstatus);
  1167.       }
  1168.  
  1169.       if (afterRecs > 0) {
  1170.      value = (Byte *) value + (beforeRecs * Var->NphyRecBytes);
  1171.      if (bitset(Var->VDR.Flags,VAR_FILLVALUE_BIT)) {
  1172.        Nvalues = afterRecs * Var->NphyRecValues;
  1173.        for (valueN = 0; valueN < Nvalues; valueN++)
  1174.           memmove ((Byte *) value + valueN*Var->NvalueBytes,
  1175.                Var->VDR.FillValue, Var->NvalueBytes);
  1176.      }
  1177.      else {
  1178.        Nelements = afterRecs * Var->NphyRecValues * Var->VDR.NumElem;
  1179.        for (elemN = 0; elemN < Nelements; elemN++)
  1180.           memmove ((Byte *) value + elemN*_CDFelemSizes[Var->VDR.DataType],
  1181.                _CDFdefaultFillValues[Var->VDR.DataType],
  1182.                _CDFelemSizes[Var->VDR.DataType]);
  1183.      }
  1184.      STATUSdisp (VIRTUAL_RECORD_DATA, Pstatus);
  1185.       }
  1186.   }
  1187.   else { /*** put ***/
  1188.       offset = _CURcdf->recnum * Var->NphyRecBytes;
  1189.       Tstatus = HyperPutBytes (Var, offset,
  1190.                    _CURcdf->reccount * Var->NphyRecBytes, value);
  1191.       STATUSdisp (Tstatus, Pstatus);
  1192.   }
  1193.   return Pstatus;
  1194. }
  1195.  
  1196. /******************************************************************************
  1197. * ...not a contiguous strip of records, do it one record at a time.
  1198. ******************************************************************************/
  1199.  
  1200. if (full_contig_records) striplen = Var->NphyRecBytes;
  1201.  
  1202. recTop = _CURcdf->recnum + (_CURcdf->reccount-1) * _CURcdf->recinterval;
  1203.  
  1204. for (rec_n = _CURcdf->recnum; rec_n <= recTop; rec_n += _CURcdf->recinterval)
  1205.    if (bitset(Var->VDR.Flags,VAR_RECVARY_BIT) || rec_n == _CURcdf->recnum) {
  1206.      /*************************************************************************
  1207.      * Don't propagate if the record variance is VARY or if this is the first
  1208.      * record (VARY or NOVARY).  If the latter case, we have to get at least
  1209.      * the first record (and then propagate the remaining records if the record
  1210.      * variance is NOVARY).
  1211.      *************************************************************************/
  1212.  
  1213.       if (get && rec_n > Var->VDR.MaxRec &&
  1214.       !(bitclr(Var->VDR.Flags,VAR_RECVARY_BIT) && Var->VDR.MaxRec != -1)) {
  1215.      /*********************************************************************
  1216.      * This variable doesn't have as many physical records actually written
  1217.      * as does the entire CDF have 'virtual' records (meaning that SOME
  1218.      * variable has that many physical records).  There is a special case
  1219.      * to be checked for.  If the record variance is NOVARY and there has
  1220.      * been a record written (record 0), then we need to read the first
  1221.      * record (record 0) regardless of the first record actually requested.
  1222.      *********************************************************************/
  1223.  
  1224.      if (bitset(Var->VDR.Flags,VAR_FILLVALUE_BIT)) {
  1225.        long Nvalues;
  1226.        Nvalues = hypRecSize / Var->NvalueBytes;
  1227.        for (valueN = 0; valueN < Nvalues; valueN++)
  1228.           memmove ((Byte *) value + valueN*Var->NvalueBytes,
  1229.                Var->VDR.FillValue, Var->NvalueBytes);
  1230.      }
  1231.      else {
  1232.        long Nelements;
  1233.        Nelements = hypRecSize / _CDFelemSizes[Var->VDR.DataType];
  1234.        for (elemN = 0; elemN < Nelements; elemN++)
  1235.           memmove ((Byte *) value + elemN*_CDFelemSizes[Var->VDR.DataType],
  1236.                _CDFdefaultFillValues[Var->VDR.DataType],
  1237.                _CDFelemSizes[Var->VDR.DataType]);
  1238.      }
  1239.      value = (Byte *) value + hypRecSize;
  1240.      STATUSdisp (VIRTUAL_RECORD_DATA, Pstatus);
  1241.       }
  1242.       else {
  1243.          /*********************************************************************
  1244.      * Read/write from/to variable file.  A record offset of zero is used
  1245.      * if the record variance is NOVARY.
  1246.          *********************************************************************/
  1247.  
  1248.          if (bitset(Var->VDR.Flags,VAR_RECVARY_BIT)) {
  1249.        if (bitclr(_CURcdf->CDR.Flags,CDF_FORMAT_BIT))
  1250.          recOffset = rec_n * Var->NphyRecBytes;
  1251.        else
  1252.          SINGLErecOffsetB (Var, rec_n, recOffset);
  1253.      }
  1254.          else {
  1255.        if (bitclr(_CURcdf->CDR.Flags,CDF_FORMAT_BIT))
  1256.          recOffset = 0;
  1257.        else
  1258.          SINGLErecOffsetB (Var, 0, recOffset);
  1259.      }
  1260.  
  1261.          if (idim != one_access_idim) {
  1262.         for (dimN = 0; dimN < numDims; dimN++)
  1263.            Var->hypIndices[dimN] = _CURcdf->indices[dimN];
  1264.  
  1265.            complete = FALSE;
  1266.         physical = TRUE;
  1267.         updim = idim;
  1268.  
  1269.            while ( ! complete) {
  1270.            if (physical) {
  1271.            INDICESoffsetB (numDims, Var, Var->hypIndices,
  1272.                    indicesOffset);
  1273.            offset = recOffset + indicesOffset;
  1274.  
  1275.            if (get)
  1276.              Tstatus = HyperGetBytes (Var, offset, striplen, value);
  1277.            else
  1278.              Tstatus = HyperPutBytes (Var, offset, striplen, value);
  1279.            STATUSdisp (Tstatus, Pstatus);
  1280.  
  1281.            value = (Byte *) value + striplen;
  1282.            }
  1283.            else {
  1284.            movelen = Var->hypProducts[updim] * Var->NvalueBytes;
  1285.            if (get) memmove (value, (Byte *) value - movelen, movelen);
  1286.            value = (Byte *) value + movelen;
  1287.            }
  1288.  
  1289.            if (row_major)
  1290.               incr_hypIndices_ROW (Var->hypIndices, idim,
  1291.                        _CURcdf->indices, _CURcdf->intervals,
  1292.                        Var->hypTops, Var->VDR.DimVarys,
  1293.                        &complete, &physical, &updim);
  1294.             else
  1295.               incr_hypIndices_COL (numDims, Var->hypIndices, idim,
  1296.                        _CURcdf->indices, _CURcdf->intervals,
  1297.                        Var->hypTops, Var->VDR.DimVarys,
  1298.                        &complete, &physical, &updim);
  1299.         }
  1300.          }
  1301.          else {
  1302.         if (full_contig_records)
  1303.           offset = recOffset;
  1304.         else {
  1305.           INDICESoffsetB (numDims, Var, _CURcdf->indices, indicesOffset);
  1306.           offset = recOffset + indicesOffset;
  1307.         }
  1308.         if (get)
  1309.            Tstatus = HyperGetBytes (Var, offset, striplen, value);
  1310.          else
  1311.            Tstatus = HyperPutBytes (Var, offset, striplen, value);
  1312.         STATUSdisp (Tstatus, Pstatus);
  1313.         value = (Byte *) value + striplen;
  1314.          }
  1315.       }
  1316.    }
  1317.    else {
  1318.       /************************************************************************
  1319.       * Propagate rather than actually reading from the variable file (if this
  1320.       * is a HyperGet - if a HyperPut, just skip over the data in the buffer).
  1321.       ************************************************************************/
  1322.  
  1323.       if (get) memmove (value, (Byte *) value - hypRecSize, hypRecSize);
  1324.       value = (Byte *) value + hypRecSize;
  1325.    }
  1326.  
  1327. return Pstatus;
  1328. }
  1329.